/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package edu.ieslaferreria.creditsintesis.builders;

import com.jme.bounding.BoundingBox;
import com.jme.bounding.BoundingSphere;
import com.jme.image.Texture;
import com.jme.light.DirectionalLight;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.Node;
import com.jme.scene.state.CullState;
import com.jme.scene.state.LightState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.util.TextureManager;
import com.jmex.terrain.TerrainPage;
import com.jmex.terrain.util.AbstractHeightMap;
import com.jmex.terrain.util.FaultFractalHeightMap;
import com.jmex.terrain.util.MidPointHeightMap;
import com.jmex.terrain.util.ProceduralTextureGenerator;
import edu.ieslaferreria.creditsintesis.logicgame.Parameter;
import edu.ieslaferreria.creditsintesis.logicgame.actions.ConfigurationMapEvent;
import javax.swing.ImageIcon;

/**
 *clase que contiene un mapa aleatorio que se genera al instanciarse.
 * El primer mapa que utilizemos.
 * @author josep
 */
public class RandomTerrainManager implements TerrainManager{
    String name;
    ConfigurationMapEvent event;


    public RandomTerrainManager(String name) {
        this.name = name;
    /*
     * java.lang.String name, int blockSize, int size, Vector3f stepScale, float[] heightMap, int totalSize, Vector2f offset, float offsetAmount)
     */
    }

    /**
     * build the height map and terrain block.
     */
    public TerrainPage buildTerrain(Node rootNode) {
        return this.buildTerrain(rootNode, "defaultTerrain", 257,33 , null, name);
        
    }


    public TerrainPage postBuild(Node rootNode,String name,int mapSize, int blockSize,float[] map){
        TerrainPage res;
        Vector3f terrainScale = new Vector3f(10,0.75f,10);
        res = new TerrainPage(name, blockSize, mapSize, terrainScale, map);
        res.setDetailTexture(1, 128);
        rootNode.attachChild(res);

        HeightMap heightMap=new HeightMap(map);

        ProceduralTextureGenerator pt = new ProceduralTextureGenerator(heightMap);
        pt.addTexture(new ImageIcon(RandomTerrainManager.class.getClassLoader()
                            .getResource("texture/grass.jpg")), -128, 0, 128);
        pt.addTexture(new ImageIcon(RandomTerrainManager.class.getClassLoader()
                            .getResource("texture/dirt.jpg")), 0, 128, 255);
        pt.addTexture(new ImageIcon(RandomTerrainManager.class.getClassLoader()
                            .getResource("texture/highest.jpg")), 128, 255, 512);
        pt.createTexture(512);

            // assign the texture to the terrain
        TextureState ts =  DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
        ts.setEnabled(true);
        Texture t1 = TextureManager.loadTexture(pt.getImageIcon().getImage(),
              Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear, true);
        ts.setTexture(t1, 0);

        Texture t2 = TextureManager.loadTexture(RandomTerrainManager.class
                     .getClassLoader().getResource("texture/Detail.jpg"),
                                    Texture.MinificationFilter.Trilinear,
                                    Texture.MagnificationFilter.Bilinear);
        ts.setTexture(t2, 1);
        t2.setWrap(Texture.WrapMode.Repeat);

        t1.setApply(Texture.ApplyMode.Combine);
        t1.setCombineFuncRGB(Texture.CombinerFunctionRGB.Modulate);
        t1.setCombineSrc0RGB(Texture.CombinerSource.CurrentTexture);
        t1.setCombineOp0RGB(Texture.CombinerOperandRGB.SourceColor);
        t1.setCombineSrc1RGB(Texture.CombinerSource.PrimaryColor);
        t1.setCombineOp1RGB(Texture.CombinerOperandRGB.SourceColor);
        t1.setCombineScaleRGB(Texture.CombinerScale.One);

        t2.setApply(Texture.ApplyMode.Combine);
        t2.setCombineFuncRGB(Texture.CombinerFunctionRGB.AddSigned);
        t2.setCombineSrc0RGB(Texture.CombinerSource.CurrentTexture);
        t2.setCombineOp0RGB(Texture.CombinerOperandRGB.SourceColor);
        t2.setCombineSrc1RGB(Texture.CombinerSource.Previous);
        t2.setCombineOp1RGB(Texture.CombinerOperandRGB.SourceColor);
        t2.setCombineScaleRGB(Texture.CombinerScale.One);

        res.setRenderState(ts);
        return res;


    }

    /**
     * creates a light for the terrain.
     */
    public LightState buildLighting() {
            /** Set up a basic, default light. */
        DirectionalLight light = new DirectionalLight();
        light.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
        light.setAmbient(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f));
        light.setDirection(new Vector3f(1,-1,0));
        light.setEnabled(true);

          /** Attach the light to a lightState and the lightState to rootNode. */
        LightState lightState = DisplaySystem.getDisplaySystem().getRenderer()
                                                              .createLightState();
        lightState.setEnabled(true);
        lightState.attach(light);
        return lightState;
    }

    public Sky buildSky(Node rootNode, TerrainPage terrain) {
        return buildSkyDome(rootNode, terrain);
    }

    public SkyDome buildSkyDome(Node rootNode, TerrainPage terrain) {
        SkyDome dome = new SkyDome("skyDome", new Vector3f(0.0f,0.0f,0.0f), 11, 18, 850.0f);
        dome.setModelBound(new BoundingSphere());
        dome.updateModelBound();
        dome.updateRenderState();
        dome.setUpdateTime(5.0f);
        dome.setTimeWarp(780.0f);
        dome.setDay(267);
        dome.setLatitude(-22.9f);
        dome.setLongitude(-47.083f);
        dome.setStandardMeridian(-45.0f);
        dome.setSunPosition(5.75f);             // 5:45 am
        dome.setTurbidity(2.0f);
        dome.setSunEnabled(true);
        dome.setExposure(true, 18.0f);
        dome.setOvercastFactor(0.0f);
        dome.setGammaCorrection(2.5f);
        dome.setRootNode(rootNode);
        dome.setIntensity(1.0f);
        // setup a target to LightNode, if you dont want terrain with light's effect remove it.
        dome.setTarget(terrain);
        rootNode.attachChild(dome);
        return dome;
    }

    public ConfigurationMapEvent getEvent() {
        return this.event;
    }

    public TerrainPage buildRemoteTerrain(Node rootNode, String name, int blocksize, int size, Vector3f vector3f, float[] map, String modelTerrainName) {
        TerrainPage res;
        this.preBuild(rootNode);
        res=postBuild(rootNode,name,size, blocksize, map);
        return res;
    }

    public TerrainPage buildTerrain(Node rootNode, String name, int blocksize, int size, Vector3f vector3f, String modelName) {
        TerrainPage res;
        this.preBuild(rootNode);
        FaultFractalHeightMap heightMap = new FaultFractalHeightMap(size, 32, 0, 255, 0.75f);
        heightMap.setHeightScale( 0.001f);
        res=postBuild(rootNode,name,heightMap.getSize(), blocksize,heightMap.getHeightMap());
        this.event= new ConfigurationMapEvent(modelName);
        this.event.addParameter("Name", new Parameter(name));
        this.getEvent().addParameter("Blocksize",new Parameter(blocksize));
        this.getEvent().addParameter("Size",new Parameter(size));
        this.getEvent().addParameter("Vector3f",new Parameter(vector3f));
        this.getEvent().addParameter("Map",new Parameter(heightMap.getHeightMap()));




        return res;
    }
    private void preBuild(Node rootNode){

        CullState cs = DisplaySystem.getDisplaySystem().getRenderer().createCullState();
        cs.setCullFace(CullState.Face.Back);
        cs.setEnabled(true);
        rootNode.setRenderState(cs);

    }

    private class HeightMap extends AbstractHeightMap{

        public HeightMap(float []map){
            this.heightData=map;
        }

        @Override
        public boolean load() {
            return true;
        }

    }

}
